﻿using System;
using System.Configuration;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Threading;
using GurLoader.GlobalHotkey;
using GurLoader.Preferences;
using GurLoader.Service.HotKeyManager;
using GurLoader.Service.ImgurTaskBuilder;
using GurLoader.Service.MessageProcessing;
using GurLoader.Service.ScreenshotUpload;
using GurLoader.Service.TaskExecution;
using GurLoader.Util;
using GurLoader.View;
using GurLoader.ViewModel;
using Hardcodet.Wpf.TaskbarNotification;
using Imgur.Net;
using Imgur.Net.Auth;

namespace GurLoader
{
    /// <summary>
    ///     Interaction logic for App.xaml
    /// </summary>
    [ExcludeFromCodeCoverage]
    public partial class App : Application
    {
        private IAppConfiguration AppConfiguration { get; set; }
        private TaskbarIcon TaskbarIcon { get; set; }
        private GurLoaderPreferences AppPreferences { get; set; }
        private ITaskExecutionService ExecutionService { get; set; }
        private IHotKeyManagerService HotKeyManager { get; set; }
        private IViewBuilder ViewBuilder { get; set; }
        private ICommandManager CommandManager { get; set; }

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            AppConfiguration = new DefaultAppConfiguration();
            CommandManager = new CommandManagerWrapper();

            IDispatcher dispatcher = new DefaultDispatcherWrapper();

            ViewBuilder = new DefaultViewBuilder();

            AppPreferences = GurLoaderPreferences.Load(new LocalIOFileOperations());

            TaskbarIcon = (TaskbarIcon) FindResource("TaskbarIcon");
            TaskbarIcon.DataContext = new NotifyTrayViewModel(AppPreferences, new ApplicationWrapper(this), CommandManager);

            ImgurAuthProvider authProvider = CreateAuthProvider(AppPreferences.UseAnonymousContext, dispatcher);

            IImageProvider imageProvider = new ImageProviderWrapper( new DefaultImageProvider( authProvider ) );
            IAlbumProvider albumProvider = new AlbumProviderWrapper( new DefaultAlbumProvider( authProvider ) );

            AppPreferences.AuthContextTypeChanged += (sender, args) =>
            {
                ImgurAuthProvider updatedAuthProvider = CreateAuthProvider(args.UseAnonymousAuthContext, dispatcher);

                imageProvider.UpdateAuthProvider(updatedAuthProvider);
                albumProvider.UpdateAuthProvider(updatedAuthProvider);
            };

            ITaskBuilderService imgurExecutionService =
                new ImgurTaskBuilderService(imageProvider, albumProvider);

            ExecutionService = new DefaultTaskExecutionService(Current.Dispatcher, ViewBuilder);

            ScreenshotUploadService screenshotUploadService = new ScreenshotUploadService(imgurExecutionService, ExecutionService, ViewBuilder, dispatcher, CommandManager, AppPreferences);

            HotKeyManager = new HotKeyManagerService(
                AppPreferences, 
                dispatcher, 
                screenshotUploadService, 
                ViewBuilder,
                new DefaultHwndSourceFactory(),
                new DefaultWindowsHotkeyProvider());
            

            HotKeyManager.CreateBindings();

            MessageProcessingService service = new MailslotMessageProcessingService(imgurExecutionService, dispatcher, AppPreferences);

            var loop = new ListenerLoop(AppPreferences, service, AppConfiguration);

            loop.CommandPrepared += OnCommandPrepared;
            loop.Start();
        }

        protected virtual ImgurAuthProvider CreateAuthProvider(bool isAnonymous, IDispatcher dispatcher)
        {
            ImgurAuthProvider authProvider;

            if (isAnonymous)
                authProvider = new AnonymousAuthenticationProvider(AppConfiguration.Settings["clientId"]);
            else
            {
                RegistrationTokenContext currentContext = AppPreferences.RegistrationTokens;
                if (currentContext == null)
                    currentContext = new DefaultRegistrationTokenContext(string.Empty, string.Empty, DateTime.Now);

                authProvider = new RegisteredAuthenticationProvider(
                    AppConfiguration.Settings["clientId"], AppConfiguration.Settings["clientSecret"],
                    currentContext, uri =>
                    {
                        RegistrationTokenContext newTokenContext = null;
                        dispatcher.Invoke(new Action(() =>
                        {
                            AuthUtils authUtils = new AuthUtils();
                            LoginViewModel vm = new LoginViewModel(uri);
                            IWindow window = ViewBuilder.CreateLoginWindow(vm);
                            vm.CurrentUriChanged += (sender, uriChangedArgs) =>
                            {
                                try
                                {
                                    newTokenContext = authUtils.ParseOAuthResponse(uriChangedArgs.CurrentUri);
                                    window.CloseWindow();
                                }
                                // ReSharper disable once EmptyGeneralCatchClause
                                catch
                                {

                                }
                            };

                            window.ShowDialogWindow();
                        }),
                        DispatcherPriority.Normal, null);

                        return newTokenContext;
                    });
                ((RegisteredAuthenticationProvider)authProvider).RegistrationTokensChanged += (sender, args) =>
                {
                    AppPreferences.RegistrationTokens = args.RegistrationTokens;
                };
            }

            return authProvider;
        }

        private void OnCommandPrepared(object sender, CommandPreparedEventArgs args)
        {
            ExecutionService.ExecuteTask(args.Task, args.Progress, args.CancellationTokenSource, CommandManager);
        }

        protected override void OnExit(ExitEventArgs e)
        {
            TaskbarIcon.Dispose();
            HotKeyManager.Dispose();
            base.OnExit(e);
        }
    }
}